home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
Python 1.3.3
/
Python 133 SRC
/
Extensions
/
img
/
dither.c
next >
Wrap
C/C++ Source or Header
|
1995-12-21
|
7KB
|
247 lines
/*
** dither - Dither a 24-bit color image to an 8 bit mapped image.
**
** Jack Jansen, CWI, 1995.
**
** Modified from ppmquant.c, which is
** Copyright (C) 1989, 1991 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
#include "Python.h"
#include "mppmcmap.h"
#define MAXCOLORS 32767
int
mppm_dither(pixels, cols, rows, colormap, newcolors, floyd, result)
pixel *pixels;
int cols, rows;
pixel *colormap;
int newcolors;
int floyd;
unsigned char *result;
{
#if 0
int
main( argc, argv )
int argc;
char* argv[];
{
FILE* ifp;
pixel** pixels;
pixel** mappixels;
register pixel* pP;
int argn, rows, cols, maprows, mapcols, row;
register int col, limitcol;
pixval maxval, newmaxval, mapmaxval;
int newcolors, colors;
register int ind;
colorhist_vector chv, colormap;
int floyd;
char* usage = "[-floyd|-fs] <ncolors> [ppmfile]\n [-floyd|-fs] -map mapfile [ppmfile]";
#endif
colorhash_table cht;
int usehash;
long thispixel;
int ind;
long* thisrerr;
long* nextrerr;
long* thisgerr;
long* nextgerr;
long* thisberr;
long* nextberr;
long* temperr;
register long sr, sg, sb, err;
#define FS_SCALE 1024
int fs_direction;
int col, limitcol, row;
register pixel* pP;
/*
** Step 4: map the colors in the image to their closest match in the
** new colormap, and write 'em out.
*/
cht = mppm_alloccolorhash( );
usehash = 1;
if ( floyd )
{
/* Initialize Floyd-Steinberg error vectors. */
thisrerr = (long*) calloc( cols + 2, sizeof(long) );
nextrerr = (long*) calloc( cols + 2, sizeof(long) );
thisgerr = (long*) calloc( cols + 2, sizeof(long) );
nextgerr = (long*) calloc( cols + 2, sizeof(long) );
thisberr = (long*) calloc( cols + 2, sizeof(long) );
nextberr = (long*) calloc( cols + 2, sizeof(long) );
if ( !thisrerr || !nextrerr || !thisgerr ||
!nextgerr || !thisberr || !nextberr )
return -1;
#ifdef macintosh
srand(time(0));
#else
srand( (int) ( time( 0 ) ^ getpid( ) ) );
#endif
for ( col = 0; col < cols + 2; ++col )
{
thisrerr[col] = rand( ) % ( FS_SCALE * 2 ) - FS_SCALE;
thisgerr[col] = rand( ) % ( FS_SCALE * 2 ) - FS_SCALE;
thisberr[col] = rand( ) % ( FS_SCALE * 2 ) - FS_SCALE;
/* (random errors in [-1 .. 1]) */
}
fs_direction = 1;
}
for ( row = 0; row < rows; ++row )
{
if ( floyd )
for ( col = 0; col < cols + 2; ++col )
nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
if ( ( ! floyd ) || fs_direction )
{
col = 0;
limitcol = cols;
pP = &pixels[row*cols];
}
else
{
col = cols - 1;
limitcol = -1;
pP = &(pixels[row*cols+col]);
}
do
{
if ( floyd )
{
/* Use Floyd-Steinberg errors to adjust actual color. */
sr = MPPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
sg = MPPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
sb = MPPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
if ( sr < 0 ) sr = 0;
else if ( sr > MAXVAL ) sr = MAXVAL;
if ( sg < 0 ) sg = 0;
else if ( sg > MAXVAL ) sg = MAXVAL;
if ( sb < 0 ) sb = 0;
else if ( sb > MAXVAL ) sb = MAXVAL;
MPPM_ASSIGN( thispixel, sr, sg, sb );
} else {
thispixel = *pP;
}
/* Check hash table to see if we have already matched this color. */
ind = mppm_lookupcolor( cht, &thispixel );
if ( ind == -1 )
{ /* No; search colormap for closest match. */
register int i, r1, g1, b1, r2, g2, b2;
register long dist, newdist;
r1 = MPPM_GETR( thispixel );
g1 = MPPM_GETG( thispixel );
b1 = MPPM_GETB( thispixel );
dist = 2000000000;
for ( i = 0; i < newcolors; ++i )
{
r2 = MPPM_GETR( colormap[i] );
g2 = MPPM_GETG( colormap[i] );
b2 = MPPM_GETB( colormap[i] );
newdist = ( r1 - r2 ) * ( r1 - r2 ) +
( g1 - g2 ) * ( g1 - g2 ) +
( b1 - b2 ) * ( b1 - b2 );
if ( newdist < dist )
{
ind = i;
dist = newdist;
}
}
if ( usehash )
{
if ( mppm_addtocolorhash( cht, &thispixel, ind ) < 0 )
{
pm_message(
"out of memory adding to hash table, proceeding without it");
usehash = 0;
}
}
}
if ( floyd )
{
/* Propagate Floyd-Steinberg error terms. */
if ( fs_direction )
{
err = ( sr - (long) MPPM_GETR( colormap[ind] ) ) * FS_SCALE;
thisrerr[col + 2] += ( err * 7 ) / 16;
nextrerr[col ] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col + 2] += ( err ) / 16;
err = ( sg - (long) MPPM_GETG( colormap[ind] ) ) * FS_SCALE;
thisgerr[col + 2] += ( err * 7 ) / 16;
nextgerr[col ] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col + 2] += ( err ) / 16;
err = ( sb - (long) MPPM_GETB( colormap[ind] ) ) * FS_SCALE;
thisberr[col + 2] += ( err * 7 ) / 16;
nextberr[col ] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col + 2] += ( err ) / 16;
}
else
{
err = ( sr - (long) MPPM_GETR( colormap[ind] ) ) * FS_SCALE;
thisrerr[col ] += ( err * 7 ) / 16;
nextrerr[col + 2] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col ] += ( err ) / 16;
err = ( sg - (long) MPPM_GETG( colormap[ind] ) ) * FS_SCALE;
thisgerr[col ] += ( err * 7 ) / 16;
nextgerr[col + 2] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col ] += ( err ) / 16;
err = ( sb - (long) MPPM_GETB( colormap[ind] ) ) * FS_SCALE;
thisberr[col ] += ( err * 7 ) / 16;
nextberr[col + 2] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col ] += ( err ) / 16;
}
}
/* XXXX *pP = colormap[ind].color; */
result[col] = ind;
if ( ( ! floyd ) || fs_direction )
{
++col;
++pP;
}
else
{
--col;
--pP;
}
}
while ( col != limitcol );
if ( floyd )
{
temperr = thisrerr;
thisrerr = nextrerr;
nextrerr = temperr;
temperr = thisgerr;
thisgerr = nextgerr;
nextgerr = temperr;
temperr = thisberr;
thisberr = nextberr;
nextberr = temperr;
fs_direction = ! fs_direction;
}
/*XXXX mppm_writeppmrow( stdout, pixels[row], cols, MAXVAL, 0 ); */
result += cols;
}
/* XXXX Free temp data XXXX */
return 0;
}